package org.lazy.generate.factory;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.lazy.generate.bean.GeneratorDataSource;
import org.lazy.generate.bean.GeneratorEntity;
import org.lazy.generate.bean.GeneratorMapper;
import org.lazy.generate.bean.GeneratorTable;
import org.lazy.generate.common.XmlConstants;
import org.lazy.generate.util.FactoryUtil;

public class MapperFactory extends FileFactory{
	/**
	 * 创建MapperXml
	 */
	public static void buildMapperXml(GeneratorDataSource dataSource,GeneratorMapper mapper,GeneratorEntity entity,GeneratorTable table,ResultSetMetaData metaData) throws Exception{
		if(XmlConstants.IS_NEED_FALSE.equals(mapper.getIsNeed())){
			System.out.println("ignore : "+table.getTableName()+"build MapperXml");
			return ;
		}
		String tableName = table.getTableName();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String mapperXmlName = createMapperXmlName(entityClassName, tableName);
		String targetPath = mapper.getTargetPath();
		String mapperXmlPackage = mapper.getTargetPackage();
		String mapperXmlFilePath = targetPath+"/"+mapperXmlPackage.replace(".", "/");
		String namepace = mapperXmlPackage+"."+mapperXmlName;
		PrintWriter pw = null;
		File file = createTargetMapperXml(mapperXmlFilePath, mapperXmlName);
		try {
			pw = new PrintWriter(file);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		pw.println("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
		pw.println("<mapper namespace=\""+namepace+"\">");
		wirteResultMap(pw, metaData, entity, table);
		wirteParameterMap(pw, metaData, entity, table);
		writeSqlColums(pw, metaData, entity, table);
		writeSqlWhere(pw, metaData, entity, table);
		writeInsert(pw, metaData, entity, table);
		writeUpdateByPrimaryKey(pw, metaData, entity, table);
		writeSelectByPrimaryKey(pw, metaData,dataSource, entity, table);
		writeCountByCondition(pw, metaData, entity, table);
		writeSelectByCondition(pw, metaData, entity, table);
		writeDeleteByPrimaryKey(pw, metaData, dataSource,entity, table);
		writeDeleteBatchByPrimaryKey(pw, metaData, entity, table);
		
		pw.println("</mapper>");
		pw.flush();
		pw.close();
		System.out.println("success : "+mapperXmlName+".xml");
	}
	/**
	 * 创建MapperXml
	 */
	public static void buildMapperXmlExt(GeneratorDataSource dataSource,GeneratorMapper mapper,GeneratorEntity entity,GeneratorTable table,ResultSetMetaData metaData) throws Exception{
		if(XmlConstants.IS_NEED_FALSE.equals(mapper.getIsNeed())){
			System.out.println("ignore : "+table.getTableName()+"build MapperXmlExt");
			return ;
		}
		String tableName = table.getTableName();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String mapperXmlName = createMapperXmlName(entityClassName, tableName);
		String mapperXmlExtName = createMapperXmlExtName(entityClassName, tableName);
		String targetPath = mapper.getTargetPath();
		String mapperXmlPackage = mapper.getTargetPackage();
		String mapperXmlFilePath = targetPath+"/"+mapperXmlPackage.replace(".", "/");
		String namepace = mapperXmlPackage+"."+mapperXmlName;
		PrintWriter pw = null;
		if(!isExistXmlFile(mapperXmlFilePath, mapperXmlExtName)){
			File file = createTargetMapperXml(mapperXmlFilePath, mapperXmlExtName);
			try {
				pw = new PrintWriter(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			
			pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			pw.println("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
			pw.println("<mapper namespace=\""+namepace+"\">");
			pw.println("\n");
			pw.println("</mapper>");
			pw.flush();
			pw.close();
			System.out.println("success : "+mapperXmlExtName+".xml");
		}
	}
	/**
	 * 写入resultMap
	 * @throws Exception 
	 */
	private static void wirteResultMap(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws Exception{
		String tableName = table.getTableName();
		String primaryKey = table.getPrimaryKey();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);	
		String entityPackage = entity.getTargetPackage();
		String entityFullClassName = createFullEntityClassName(entityPackage, entityClassName);
		String resultMapID = createBaseResultMapID(entityClassName, tableName);
		pw.println(t1+"<resultMap id=\""+resultMapID+"\" type=\""+entityFullClassName+"\">");
		writeResultMapResult(pw, metaData,primaryKey);
		pw.println(t1+"</resultMap>");
	}
	/**
	 * 写入resultMap
	 * @throws Exception 
	 */
	private static void wirteParameterMap(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws Exception{
		String tableName = table.getTableName();
		String primaryKey = table.getPrimaryKey();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);	
		String entityPackage = entity.getTargetPackage();
		String entityFullClassName = createFullEntityClassName(entityPackage, entityClassName);
		String parameterMapID = createBaseParameterMapID(entityClassName, tableName);
		pw.println(t1+"<parameterMap id=\""+parameterMapID+"\" type=\""+entityFullClassName+"\">");
		writeParameterMapResult(pw, metaData,primaryKey);
		pw.println(t1+"</parameterMap>");
	}
	/**
	 * 写入resultMap的result
	 * @throws Exception 
	 */
	private static void writeResultMapResult(PrintWriter pw,ResultSetMetaData metaData,String primaryKey) throws Exception{
		int colum = metaData.getColumnCount();
		boolean isHasId = false;
		for (int i = 1; i <= colum; i++) {
			String columnName = metaData.getColumnName(i);
			String filedName = createFieldName(columnName);
			if(primaryKey.toUpperCase().equals(columnName.toUpperCase())){
				isHasId = true;
			}
			pw.println(t2+"<result column=\""+columnName+"\"  property=\""+filedName+"\" />");
		}
		if(!isHasId){
			throw new Exception("表设计缺少主键字段");
		}
	}
	/**
	 * 写入ParameterMap的result
	 * @throws Exception 
	 */
	private static void writeParameterMapResult(PrintWriter pw,ResultSetMetaData metaData,String primaryKey) throws Exception{
		int colum = metaData.getColumnCount();
		boolean isHasId = false;
		for (int i = 1; i <= colum; i++) {
			String columnName = metaData.getColumnName(i);
			String filedName = createFieldName(columnName);
			if(primaryKey.toUpperCase().equals(columnName.toUpperCase())){
				isHasId = true;
			}
			pw.println(t2+"<parameter resultMap=\""+columnName+"\"  property=\""+filedName+"\" />");
		}
		if(!isHasId){
			throw new Exception("表设计缺少主键字段");
		}
	}
	/**
	 * 写入columns
	 */
	private static void writeSqlColums(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws SQLException{
		pw.println(t1+"<sql id=\"columns"+"\">");
		int colum = metaData.getColumnCount();
		StringBuffer sb = new StringBuffer();
		for (int i = 1; i <= colum; i++) {
			String columnName = metaData.getColumnName(i);
			sb.append(columnName);
			if(i!=colum){
				sb.append(",");
			}
		}
		pw.println(t2+sb.toString());
		pw.println(t1+"</sql>");
	}
	/**
	 * 写入columns
	 */
	private static void writeSqlWhere(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws SQLException{
		pw.println(t1+"<sql id=\"dynamicWhere"+"\">");
		pw.println(t2+"<where>");
		pw.println(t3+"<foreach collection=\"conditions\" item=\"c\">");
		pw.println(t4+"<choose>");
		
		pw.println(t5+"<when test=\"c.noValue\">");
		pw.println(t6+"and ${c.condition}");
		pw.println(t5+"</when>");
		
		pw.println(t5+"<when test=\"c.oneValue\">");
		pw.println(t6+"and ${c.condition} #{c.value}");
		pw.println(t5+"</when>");
		
		pw.println(t5+"<when test=\"c.betweenValue\">");
		pw.println(t6+"and ${c.condition} #{c.value} and #{c.secondValue}");
		pw.println(t5+"</when>");
		
		pw.println(t5+"<when test=\"c.inValue\">");
		pw.println(t6+"and ${c.condition}");
		pw.println(t6+"<foreach collection=\"c.value\" item=\"listItem\" open=\"(\" close=\")\" separator=\",\">");
		pw.println(t7+"${listItem}");
		pw.println(t6+"</foreach>");
		pw.println(t5+"</when>");
		
		pw.println(t4+"</choose>");
		pw.println(t3+"</foreach>");
		pw.println(t2+"</where>");
		pw.println(t1+"</sql>");
	}
	/**
	 * 写入insert
	 */
	private static void writeInsert(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws SQLException{
		String tableName = table.getTableName();
		String primaryKey = table.getPrimaryKey();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String parameterMap = createBaseParameterMapID(entityClassName, tableName);
		int colum = metaData.getColumnCount();
		pw.println(t1+"<!-- 插入一条数据 -->");
		pw.println(t1+"<insert id=\""+d_method_insert+"\" keyProperty=\""+primaryKey+"\" useGeneratedKeys=\"true\"	parameterMap=\""+parameterMap+"\">");
		pw.println(t3+"insert into "+tableName);
		pw.println(t3+"<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
		for (int i = 1; i <= colum; i++) {
			String columnName = metaData.getColumnName(i);
			String filedName = createFieldName(columnName);
			pw.println(t4+"<if test=\""+filedName+" != null\"> "+columnName+", </if>");
		}
		pw.println(t3+"</trim>");
		pw.println(t3+"<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">");
		for (int i = 1; i <= colum; i++) {
			String columnName = metaData.getColumnName(i);
			String filedName = createFieldName(columnName);
			pw.println(t4+"<if test=\""+filedName+" != null\"> #{"+filedName+"}, </if>");
		}
		pw.println(t3+"</trim>");

		pw.println(t1+"</insert>");
	}
	/**
	 * 写入selectById
	 * @throws Exception 
	 */
	private static void writeSelectByPrimaryKey(PrintWriter pw,ResultSetMetaData metaData,GeneratorDataSource dataSource,GeneratorEntity entity,GeneratorTable table) throws Exception{
		String tableName = table.getTableName();
		String tablePrimaryKey = table.getPrimaryKey();
		String entityPrimaryKey = createFieldName(tablePrimaryKey);
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String primaryKeyJavaType = FactoryUtil.getPrimaryKeyJaveType(table, metaData, dataSource.getDbType());
		String resultMapID = createBaseResultMapID(entityClassName, tableName);
		pw.println(t1+"<!-- 查询一条数据 -->");
		pw.println(t1+"<select id=\""+d_method_selectByPrimaryKey+"\" parameterType=\""+primaryKeyJavaType+"\"	resultMap=\""+resultMapID+"\">");
		pw.println(t2+"select");
		pw.println(t2+"<include refid=\"columns\" />");
		pw.println(t2+"from "+tableName);
		pw.println(t2+"where "+tablePrimaryKey+" = #{"+entityPrimaryKey+"}");
		pw.println(t1+"</select>");
	}
	/**
	 * 写入countByCondition
	 * @throws Exception 
	 */
	private static void writeCountByCondition(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws Exception{
		String tableName = table.getTableName();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String entityConditionClassName = createEntityConditionClassName(entityClassName, tableName);
		String entityConditionPackage = entity.getTargetPackage();
		String entityConditionClassNameFull = createFullEntityConditionClassName(entityConditionPackage, entityConditionClassName);
		pw.println(t1+"<!-- 统计  -->");
		pw.println(t1+"<select id=\""+d_method_countByCondition+"\" parameterType=\""+entityConditionClassNameFull+"\"	resultType=\"Long\">");
		pw.println(t2+"select");
		pw.println(t2+"count(*)");
		pw.println(t2+"from "+tableName);
		pw.println(t2+"<include refid=\"dynamicWhere\" />");
		pw.println(t1+"</select>");
	}
	/**
	 * 写入selectByCondition
	 * @throws Exception 
	 */
	private static void writeSelectByCondition(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws Exception{
		String tableName = table.getTableName();
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String entityConditionClassName = createEntityConditionClassName(entityClassName, tableName);
		String entityConditionPackage = entity.getTargetPackage();
		String entityConditionClassNameFull = createFullEntityConditionClassName(entityConditionPackage, entityConditionClassName);
		String resultMapID = createBaseResultMapID(entityClassName, tableName);
		pw.println(t1+"<!-- 根据条件查询 -->");
		pw.println(t1+"<select id=\""+d_method_selectByCondition+"\" parameterType=\""+entityConditionClassNameFull+"\"	resultMap=\""+resultMapID+"\">");
		pw.println(t2+"select");
		pw.println(t2+"<include refid=\"columns\" />");
		pw.println(t2+"from "+tableName);
		pw.println(t2+"<include refid=\"dynamicWhere\" />");
		//排序
		pw.println(t2+"<if test=\"orderByClause != null\">");
		pw.println(t3+"${orderByClause}");
		pw.println(t2+"</if>");
		//分页
		pw.println(t2+"<if test=\"isLimit\">");
		pw.println(t3+"limit ${startRow},${pageSize}");
		pw.println(t2+"</if>");
		pw.println(t1+"</select>");
	}
	/**
	 * 写入deleteById
	 * @throws Exception 
	 */
	private static void writeDeleteByPrimaryKey(PrintWriter pw,ResultSetMetaData metaData,GeneratorDataSource dataSource,GeneratorEntity entity,GeneratorTable table) throws Exception{
		String tableName = table.getTableName();
		String tablePrimaryKey = table.getPrimaryKey();
		String entityPrimaryKey = createFieldName(tablePrimaryKey);
		String primaryKeyJavaType = FactoryUtil.getPrimaryKeyJaveType(table, metaData, dataSource.getDbType());
		pw.println(t1+"<!-- 删除一条数据 -->");
		pw.println(t1+"<delete id=\""+d_method_deleteByPrimaryKey+"\" parameterType=\""+primaryKeyJavaType+"\">");
		pw.println(t2+"delete from "+tableName);
		pw.println(t2+"where");
		pw.println(t2+tablePrimaryKey+" = #{"+entityPrimaryKey+"}");
		pw.println(t1+"</delete>");
	}	
	/**
	 * 写入deleteByIdBatch
	 */
	private static void writeDeleteBatchByPrimaryKey(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws SQLException{
		String tableName = table.getTableName();
		String tablePrimaryKey = table.getPrimaryKey();
		pw.println(t1+"<!-- 批量删除数据 -->");
		pw.println(t1+"<delete id=\""+d_method_deleteBatchByPrimaryKey+"\" parameterType=\"java.util.List\">");
		pw.println(t2+"delete from "+tableName);
		pw.println(t2+"where");
		pw.println(t2+tablePrimaryKey+" in");
		pw.println(t2+"<foreach item=\"item\" index=\"index\" collection=\"list\" open=\"(\" separator=\",\" close=\")\">");
		pw.println(t3+"#{item}");
		pw.println(t2+"</foreach>");
		pw.println(t1+"</delete>");
	}	
	/**
	 * 写入updateById
	 */
	private static void writeUpdateByPrimaryKey(PrintWriter pw,ResultSetMetaData metaData,GeneratorEntity entity,GeneratorTable table) throws SQLException{
		String tableName = table.getTableName();
		String tablePrimaryKey = table.getPrimaryKey();
		String entityPrimaryKey = createFieldName(tablePrimaryKey);
		String entityName = table.getEntityName();
		String entityClassName = createEntityClassName(entityName, tableName);
		String parameterMap = createBaseParameterMapID(entityClassName, tableName);
		pw.println(t1+"<!-- 更新一条数据 -->");
		pw.println(t1+"<update id=\""+d_method_updateByPrimaryKey+"\" parameterMap=\""+parameterMap+"\">");
		pw.println(t2+"update "+tableName);
		pw.println(t2+"<set>");
		int colum = metaData.getColumnCount();
		for (int i = 1; i <= colum; i++) {
			String columnName = metaData.getColumnName(i);
			String filedName = createFieldName(columnName);
			pw.println(t3+"<if test=\""+filedName+" != null\">"+columnName+" = #{"+filedName+"}, </if>");
		}
		pw.println(t2+"</set>");
		pw.println(t2+"where "+tablePrimaryKey+" = #{"+entityPrimaryKey+"}");
		pw.println(t1+"</update>");
	}
	
	
	
}
